// 做缓存的工具 
// => 数据持久化(local或session) (数据库、请求)

// 可以选择是否是local
// 如果要存可以选择local或session

const CreateSotre=function(unLocal,maxLength){
    this.unLocal=unLocal
    this.maxLength=maxLength
    // 调用一个observe => 用来劫持缓存对象
    this.observe()
}

CreateSotre.prototype.getItem=function(type){
    // 具体用来获取缓存的方法
   const dataJson = window[this.stroageMethod].getItem(type)
    return JSON.parse(dataJson)
    
}

CreateSotre.prototype.setItem=function(type,data){
    // 具体用来设置缓存的方法
    const dataJSon=JSON.stringify(data)
    window[this.stroageMethod].setItem(type,dataJSon)
}

// 这两个方法是具体在外面的js中调用=>
// 调用set=>劫持对象的set=>做处理(N种可扩展)=>具体的触发setItem操作
CreateSotre.prototype.set=function(type,data){
    // 调用劫持对象的set
    this._mock_storage[`${this.storeKey}_${type}`]=data
}

CreateSotre.prototype.get=function(type){
    return this._mock_storage[`${this.storeKey}_${type}`]
}

let arr=['pop','push','unshift','slice','splice','reverse']
arr.forEach((method)=>{
    CreateSotre.prototype[method]=function(type,...rest){
        // 判断type有没有值
        if(!this.get(type)){
            // 缓存没有数据
            this.set(type,[])
        }
        // 有值 判断是不是数组 如果不是数组 丢掉
        if(!this.get(type) instanceof Array){
            throw Error('this data using array methods must be array!')
        }
        // 是数组
        const dataList=this.get(type)
        // 
        // 具体方法操作数据
        Array.prototype[method].apply(dataList,rest)
        // 再存缓存
        this.set(type,dataList)
    }
})

CreateSotre.prototype.observe=function(){
    const context=this
    this._mock_storage = new Proxy({},{
        get(target,key){
            // void 0 可以获取undfined
            let result=context.getItem && context.getItem(key) || void 0
            return result
        },
        set(target,key,value,receiver){
            let _value=value
            if(_value instanceof Array && _value.length>context.maxLength){
                // 说明 数组长度 大于maxLength
                _value=_value.slice(0,context.maxLength)
            }
            // 处理同步
            context.setItem && context.setItem(key,_value)
            // 处理异步:预留微任务处理缓存操作
            if(!context.unLocal){
                // context.unLocal=>false
                // 说明我的缓存数据不止存在本地还要发送请求到数据库做备份
                new Promise((resolve)=>{
                    // 发送请求，做数据备份
                    let data=1//数据回来，假设数据为1
                    resolve(data)
                }).then(res=>{
                    context.setItem && context.setItem(key,_value)
                })
            }
            return Reflect.set(target,key,value,receiver)
        }
    })
}

const CreateLocalStore=function(key,...rest){
    // key缓存名称
    // ...rest => 获取剩下的参数 unLocal,maxLength
    CreateSotre.apply(this,rest)
    // 配置缓存方式 和 缓存名称
    this.stroageMethod='localStorage'
    this.storeKey=`LOCAL_KEY_${key}`
}

CreateLocalStore.prototype=Object.create(CreateSotre.prototype)
// construcor
CreateLocalStore.prototype.constructor=CreateLocalStore

const CreateSessionStore=function(key,...rest){
    // key缓存名称
    // ...rest => 获取剩下的参数 unLocal,maxLength
    CreateSotre.apply(this,rest)
    // 配置缓存方式 和 缓存名称
    this.stroageMethod='sessionStorage'
    this.storeKey=`LOCAL_KEY_${key}`
}

CreateSessionStore.prototype=Object.create(CreateSotre.prototype)
// construcor
CreateSessionStore.prototype.constructor=CreateSessionStore

// 不管是localStore sessionStore 都是共用一套CreateSotre.prototype
// 通过组合寄生继承的方式让observe方法同时出现在localSotre.seesionStore
// 因为 xxx.getItem xxx.setItem

// 限制缓存的长度，避免数据过大
export const localStore=new CreateLocalStore('search',true,30)
export const sessionStore=new CreateSessionStore('demo',true,40)